freecivfandomcom-20200223-history
Event Scripting Common Tasks
Event that happens only once You may use the turn callback and react to a particular turn / year number for a unique event function begin_ancient_era() -- Event that happens at 2000 BC here end function turn_cb(turn, year) if year -2000 then begin_ancient_era() end end signal.connect('turn_started', 'turn_cb') You can save a flag if an event was already performed function city_was_lost(city, loser, winner) if winner:is_human() and not did_win_first_city then -- remember that we did this did_win_first_city = true -- now handle the event notify.player(winner, "Congratulations, you have taken your first city") end end signal.connect('city_lost', 'city_was_lost') -- NOTE: We don't use the 'local' word in front of the did_win_first_city variable, because this variable -- is a global variable (will be saved in the savegame) Equality test As of Freeciv 2.2, you may not use the equality operator to directly compare API objects such as players, cities, units etc. Instead you must compare objects by the id field or rule name (if applicable). For example: -- let us pretend we know that id #110 is the city of Paris paris_city_id = 110 function city_was_lost(city, loser, winner) -- see if Paris was lost if city.id paris_city_id then notify.all("Paris lost!") end -- NOTE: we can't use city find.city(paris_city_id) end function unit_was_moved(unit, src_tile, dst_tile) if unit.utype:rule_name() "Archers" then -- handle archers moved end -- NOTE: we can't use unit.utype find.unit_type("Archers") end Terrain Class You can use a lookup table to check which class of terrain a tile has function unit_was_moved(unit, src_tile, dst_tile) local bad_terrain = { Glacier = true, Desert = true, } local oceanic_terrain = { Ocean = true, Lake = true, Ocean" = true, } if bad_terraindst_tile.terrain:rule_name() then notify.player(unit.owner, "This place is not so welcoming") end end Iteration It can be practical to go through every object of a kind in a scenario script. Freeciv includes lookup functions by default in the API but no looping constructs (As of Freeciv 2.2). Here is how to define looping constructs for iteration in scripts. The following code defines * players_iterate * whole_map_iterate * unit_types_iterate * cities_iterate * units_iterate Example use: local nunits = 0 for player in players_iterate() do nunits = nunits + player:num_units() end notify.all("There are " .. nunits .. " units in the game") Implementation: (to be copied into your scenario or ruleset script) do -- iterate over the values returned by lookup -- until nil is returned: -- lookup(0), lookup(1), lookup(2), etc local function index_iterate(lookup) local index = -1 local function iterator(lookup) index = index + 1 return lookup(index) end return iterator, lookup end -- Iterate over all players of the game -- NOTE: This function needs Freeciv 2.1 or 2.2.1 (not 2.2.0) due to bugs in find.player -- In 2.2.0, it returns all 32 players of the game. function players_iterate() return index_iterate(find.player) end -- Iterate over all tiles of the game -- NOTE: This function needs Freeciv 2.2.1 due to bugs in find.tile function whole_map_iterate() return index_iterate(find.tile) end function unit_types_iterate() return index_iterate(find.unit_type) end -- NOTE: Identical further definitions can be made for -- governments, tech_types, building_types etc end do -- Iterate over a player objects (cities or units) -- lookup function takes two arguments: lookup(player, index) local function player_object_iterate(player, nobjs, lookup) local found_objs = 0 local index = -1 local function iterator() if found_objs nobjs then return nil end local obj = nil repeat index = index + 1 obj = lookup(player, index) until obj ~= nil found_objs = found_objs + 1 return obj end return iterator, nil end -- Iterate over all cities of 'player' -- if player is nil, iterate over all cities function cities_iterate(player) local ncities = 0 if player then ncities = player:num_cities() else for plr in players_iterate() do ncities = ncities + plr:num_cities() end end return player_object_iterate(player, ncities, find.city) end -- Iterate over all units of 'player' -- if player is nil, iterate over all units function units_iterate(player) local nunits = 0 if player then nunits = player:num_units() else for plr in players_iterate() do nunits = nunits + plr:num_units() end end return player_object_iterate(player, nunits, find.unit) end end Category:Event scripting